package com.github.itdachen.boot.logger.aspect;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.support.spring.PropertyPreFilters;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

/**
 * 请求日志，打印在控制台，仅在开发环境中使用
 *
 * @author 朔风
 * @date 2025-11-19 15:53
 */
@Aspect
public class LoggerDevAspect {

    public LoggerDevAspect() {
        System.out.println("======================== LoggerAspect ========================");
    }

    private final static Logger LOG = LoggerFactory.getLogger(LoggerDevAspect.class);

    /**
     * 定义一个切点，所有的 controller 层
     */
    @Pointcut("execution(public * com.github.itdachen..*Controller.*(..))")
    public void controllerPointcut() {
    }

    @Before("controllerPointcut()")
    public void doBefore(JoinPoint joinPoint) {

        // 开始打印请求日志
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Signature signature = joinPoint.getSignature();
        String name = signature.getName();

        // 打印请求信息
        LOG.info("======================== 开始 ========================");
        LOG.info("请求地址: {} {}", request.getRequestURL().toString(), request.getMethod());
        LOG.info("类名方法: {}.{}", signature.getDeclaringTypeName(), name);
        LOG.info("远程地址: {}", request.getRemoteAddr());

        String requestValue = getRequestValue(joinPoint);

        // 排除字段，敏感字段或太长的字段不显示：身份证、手机号、邮箱、密码等
        String[] excludeProperties = {};
        PropertyPreFilters filters = new PropertyPreFilters();
        PropertyPreFilters.MySimplePropertyPreFilter excludefilter = filters.addFilter();
        excludefilter.addExcludes(excludeProperties);


        LOG.info("请求参数: {}", JSONObject.toJSONString(requestValue, excludefilter));
    }

    @Around("controllerPointcut()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = proceedingJoinPoint.proceed();
        // 排除字段，敏感字段或太长的字段不显示：身份证、手机号、邮箱、密码等
        String[] excludeProperties = {};
        PropertyPreFilters filters = new PropertyPreFilters();
        PropertyPreFilters.MySimplePropertyPreFilter excludefilter = filters.addFilter();
        excludefilter.addExcludes(excludeProperties);
        LOG.info("返回结果: {}", JSONObject.toJSONString(result, excludefilter));
        LOG.info("======================== 结束 耗时：{} ms ========================", System.currentTimeMillis() - startTime);
        return result;
    }


    /**
     * 获取请求的参数
     */
    private String getRequestValue(JoinPoint joinPoint) {
        try {

            Signature signature1 = joinPoint.getSignature();
            MethodSignature signature = (MethodSignature) signature1;
            if (signature.getMethod().getName().contains("initBinder")) {
                return "{}";
            }

            if (joinPoint.getArgs()[0] instanceof MultipartFile) {
                return ((MultipartFile) joinPoint.getArgs()[0]).getOriginalFilename();
            }

            Object[] args = joinPoint.getArgs();
            int length = args.length;
            if (0 == length) {
                return "{}";
            }
            if (1 == length) {
                return JSONObject.toJSONString(joinPoint.getArgs());
            } else {
                return JSONObject.toJSONString(args[length - 1]);
            }
        } catch (Exception e) {
            return "{}";
        }


    }


}
